using System;
using System.Collections.ObjectModel;
using VisualWip.Core.Interfaces;

namespace VisualWip.Core.Columns
{
    public abstract class WorkColumnBase : WorkItemsColumnBase
    {
        private bool _showWorkInProgressLimit = true;
        private readonly ObservableCollection<Slot> _slots;
        private int _totalWorkInProgressLimit;
        private readonly ObservableCollection<WorkItem> _workItems;

        protected WorkColumnBase():base()
        {
            _slots = new ObservableCollection<Slot>();
            _workItems = new ObservableCollection<WorkItem>();
        }

        public int TotalWorkInProgressLimit
        {
            get { return _totalWorkInProgressLimit; }
            set
            {
                if (value != _totalWorkInProgressLimit)
                {
                    _totalWorkInProgressLimit = value;
                    OnPropertyChanged(this, () => TotalWorkInProgressLimit);
                    OnPropertyChanged(this, () => WorkInProgressLimit);
                    OnPropertyChanged(this, () => HasWorkInProgressLimit);
                    OnPropertyChanged(this, () => IsOverWorkInProgressLimit);
                    OnPropertyChanged(this, () => IsAtWorkInProgressLimit);
                    OnPropertyChanged(this, () => IsInWorkInProgressLimit);
                    OnPropertyChanged(this, () => WorkInProgress);

                }
            }
        }

        public virtual int WorkInProgressLimit
        {
            get { return _totalWorkInProgressLimit; }
        }

        public bool HasWorkInProgressLimit
        {
            get { return TotalWorkInProgressLimit > 0; }
        }

        public bool ShowWorkInProgressLimit
        {
            get { return _showWorkInProgressLimit; }
            set
            {
                if (value != _showWorkInProgressLimit)
                {
                    _showWorkInProgressLimit = value;
                    OnPropertyChanged(this, () => ShowWorkInProgressLimit);
                }
            }
        }

        public virtual ISlotsProvider SlotsProvider { get; protected set; }

        public virtual bool IsOverWorkInProgressLimit
        {
            get { return WorkInProgressLimit < WorkInProgress; }
        }

        public virtual bool IsAtWorkInProgressLimit
        {
            get { return WorkInProgressLimit == WorkInProgress; }
        }

        public virtual bool IsInWorkInProgressLimit
        {
            get { return WorkInProgressLimit >= WorkInProgress; }
        }

        public Collection<Slot> Slots
        {
            get { return _slots; }
        }

        public virtual int WorkInProgress
        {
            get { return _workItems.Count; }
        }

        public override PersistenceTree Persist(string name)
        {
            PersistenceTree settings = base.Persist(name);
            settings.Add(() => TotalWorkInProgressLimit);
            settings.AddChild(() => WorkItemSize);
            return settings;
        }

        public override void Load(PersistenceTree settings)
        {
            base.Load(settings);
            TotalWorkInProgressLimit = settings.Get(() => TotalWorkInProgressLimit,0);
            WorkItemSize = settings.GetChild(() => WorkItemSize, new LargeWorkItemSize());
        }

        public override void DoRefresh()
        {
            ClearWork();
            GetWork();
            ClearSlots();
            GetSlots();
        }

        private void PopulateSlots()
        {
            for (int slotCounter = 0; slotCounter < _slots.Count; slotCounter++)
            {
                if (WorkInProgress > slotCounter)
                {
                    _slots[slotCounter].WorkItem = _workItems[slotCounter];
                }
                else
                {
                    _slots[slotCounter].WorkItem = new NoWorkItem();
                }
            }
        }

        protected virtual void GetSlots()
        {
            foreach (
                Slot slot in
                    SlotsProvider.GetSlots(WorkInProgressLimit, WorkInProgress))
            {
                _slots.Add(slot);
            }

            PopulateSlots();

            OnPropertyChanged(this, () => Slots);
        }

        private void ClearSlots()
        {
            _slots.Clear();
        }

        protected virtual void GetWork()
        {
            var workQuery = GetWorkQuery();
            if (workQuery == null)
                return;
            foreach (WorkItem workItem in workQuery.RunQuery())
            {
                _workItems.Add(workItem);
            }
        }

        protected virtual IQuery GetWorkQuery()
        {
            return Query;
        }

        private void ClearWork()
        {
            _workItems.Clear();
        }
    }
}